package online.longzipeng.back.utils;

import cn.hutool.core.util.ObjectUtil;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

/**
 * @author longzipeng
 * 大数工具类
 */
public class BigDecimalUtils {

    // 默认大数保留6位小数
    public static final int DEFAULT_SCALE = 6;

    // 默认大数除法 结果规则 四舍五入 向下舍入
    public static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_DOWN;
    // 默认保留n位有效数字
    public static final int DEFAULT_PRECISION = 2;
    // 大数一百、一千、一万
    public static final BigDecimal ONE_HUNDRED = new BigDecimal("100");
    public static final BigDecimal ONE_THOUSAND = new BigDecimal("1000");
    public static final BigDecimal TEN_THOUSAND = new BigDecimal("10000");

    /**
     * 通用大数除法
     *
     * @param number1 运算的数1
     * @param number2 运算的数2
     * @return
     */
    public static BigDecimal divide(Object number1, Object number2) {
        BigDecimal b1 = castToBigDecimal(number1);
        BigDecimal b2 = castToBigDecimal(number2);
        return divide(b1, b2, DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
    }

    // 重载大数方法除法
    public static BigDecimal divide(Object number1, Object number2, int scale) {
        BigDecimal b1 = castToBigDecimal(number1);
        BigDecimal b2 = castToBigDecimal(number2);
        return divide(b1, b2, scale, DEFAULT_ROUNDING_MODE);
    }

    // 如果结果为0 则返回0
    public static BigDecimal divide(Object number1, Object number2, int scale, RoundingMode roundingMode) {
        if (ObjectUtil.isNull(number2) || ObjectUtil.equal(number2, BigDecimal.ZERO)) {
            return BigDecimal.ZERO;
        }
        BigDecimal b1 = castToBigDecimal(number1);
        BigDecimal b2 = castToBigDecimal(number2);
        return b1.divide(b2, scale, roundingMode);
    }

    public static BigDecimal divide(Object number1, Object number2, RoundingMode roundingMode) {
        BigDecimal b1 = castToBigDecimal(number1);
        BigDecimal b2 = castToBigDecimal(number2);
        return divide(b1, b2, DEFAULT_SCALE, roundingMode);
    }

    /**
     * number1 除n个数
     *
     * @param number1
     * @param numbers
     * @return
     */
    public static BigDecimal divide(Object number1, Object... numbers) {
        BigDecimal b1 = castToBigDecimal(number1);
        if (numbers.length > 0) {
            for (Object number : numbers) {
                b1 = divide(b1, number, DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
            }
        }
        return b1;
    }

    /**
     * 通用大数乘法
     *
     * @param number1
     * @param number2
     * @return
     */
    public static BigDecimal multiply(Object number1, Object number2) {
        BigDecimal b1 = castToBigDecimal(number1);
        BigDecimal b2 = castToBigDecimal(number2);
        return b1.multiply(b2);
    }

    /**
     * 重载 n个数相乘
     *
     * @param numbers
     * @return
     */
    public static BigDecimal multiply(Object... numbers) {
        BigDecimal ans = null;
        if (numbers.length > 0) {
            ans = castToBigDecimal(numbers[0]);
            if (numbers.length > 1) { // 循环相乘
                for (int i = 1; i < numbers.length; i++) {
                    ans = multiply(ans, numbers[i]);
                }
            }
        }
        return ans;
    }

    /**
     * 默认向下取整
     *
     * @param number
     * @return
     */
    public static Integer castToInteger(BigDecimal number) {
        return number.setScale(0, BigDecimal.ROUND_DOWN).intValue();
    }


    /**
     * 将对象转化为大数
     *
     * @param obj
     * @return
     */
    public static BigDecimal castToBigDecimal(Object obj) {
        if (obj == null) {
            return BigDecimal.ZERO;
        } else {
            return obj instanceof BigDecimal ? (BigDecimal) obj : new BigDecimal(obj.toString());
        }
    }

    /**
     * 获取大数的小数位数
     *
     * @param b
     * @return
     */
    public static Integer getDecimalPlaces(BigDecimal b) {
        if (ObjectUtil.isNotNull(b)) {
            // 判断如果为整数则直接返回0   过滤掉   xxx.000000的情况
            if (ObjectUtil.equal(new BigDecimal(b.intValue()), b)) {
                return 0;
            }
            // 否则进行位数判断
            String str = b.toString();
            int index = str.indexOf(".");
            if (index == -1) {
                return 0;
            }
            return str.substring(index + 1).length();
        }
        return null;
    }

    /**
     * 保留n位小数
     *
     * @param b            大数
     * @param scale        保留几位小数
     * @param roundingMode 保留小数的规则
     * @return
     */
    public static BigDecimal setScala(BigDecimal b, int scale, RoundingMode roundingMode) {
        return b.setScale(scale, roundingMode);
    }

    public static BigDecimal setScala(BigDecimal b, int scale) {
        return b.setScale(scale, DEFAULT_ROUNDING_MODE);
    }

    public static BigDecimal setScala(BigDecimal b) {
        return b.setScale(DEFAULT_SCALE);
    }

    /**
     * 保留n位有效数字
     * 1.如果为整数或者一位小数则直接返回，
     * 2.多位小数，且前两位小数有值则保留两位小数。没值则保留两位有效数字
     *
     * @param b
     * @param precision 有效数字精度
     * @param isCastInt 是否保留整数
     * @return
     */
    public static BigDecimal setEffectiveNumber(Object b, int precision, boolean isCastInt) {
        if (b == null) {
            return null;
        }
        BigDecimal bBig = castToBigDecimal(b);
        // 需要转换为int，那么大于1的话就转换为Int
        if (isCastInt && bBig.compareTo(BigDecimal.ONE) > 0) {
            return new BigDecimal(bBig.intValue());
        }

        // 获取小数位数
        Integer decimalPlaces = getDecimalPlaces(bBig);
        if (ObjectUtil.isNotNull(decimalPlaces)) {
            // 为整数返回整数部分 将 xx.000转换为xx
            if (ObjectUtil.equal(decimalPlaces, Integer.valueOf(0))) {
                return new BigDecimal(bBig.intValue());
            }
            // 一位小数则直接返回
            if (decimalPlaces.equals(Integer.valueOf("1"))) {
                return bBig;
            }
            // 值大于0时 保留两位数字
            if (bBig.compareTo(BigDecimal.ONE) > 0) {
                return setScala(bBig, precision);
            } else { // 小于0时，保留precision位有效数字
                return bBig.round(new MathContext(precision, RoundingMode.HALF_UP));
            }
        }
        return null;
    }

    public static BigDecimal setEffectiveNumber(Object b, boolean isCastInt) {
        return setEffectiveNumber(b, DEFAULT_PRECISION, isCastInt);
    }

    /**
     * 默认保留2位有效数字
     */
    public static BigDecimal setEffectiveNumber(Object b, int precision) {
        return setEffectiveNumber(b, precision, false);
    }

    public static BigDecimal setEffectiveNumber(Object b) {
        return setEffectiveNumber(b, DEFAULT_PRECISION, false);
    }

}
